<?php

/**
 * OSECORE
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the GNU General Public License version 3
 * that is bundled with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://www.gnu.org/licenses/gpl-3.0.html
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@osecore.com so we can send you a copy immediately.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade OSECORE to newer
 * versions in the future. If you wish to customize OSECORE for your
 * needs please refer to http://www.osecore.com for more information.
 *
 * @copyright	Copyright (C) 2011 by Sang Le Tuan (http://www.osecore.com). All rights reserved.
 * @license     http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License version 3
 * @author      Sang Le Tuan - batsatla@gmail.com
 */

/**
 * OSECORE Core
 *
 * @package OSECORE_Core_Request
 * @author  Le Tuan Sang <batsatla@gmail.com>
 */
class OSCCore_Request extends OSCObject {
	
	protected $_touch = false;
    protected $_getData = array();
    protected $_postData = array();
    /**
     * Is AJAX request ?
     *
     * @var boolean
     */
    protected $_ajax = false;
    /**
     * @var string
     */
    protected $_aliasKey = '';
    /**
     *
     * @var array
     */
    protected $_aliasGetKeys = array();
    /**
     *
     * @var OSCCore_Request
     */
    protected static $_instance = null;

    /**
     *
     * @return OSCCore_Request
     */
    public static function getInstance() {
        if (self::$_instance === null) {
            $class = get_class();
            self::$_instance = new $class();
        }

        return self::$_instance;
    }

    /**
     * Initialize function. Load, clean & push $_POST, $_GET to OSCCore_Request::$_in, and to determine if there is AJAX request.
     *
     * @return Boolean
     */
 protected function __construct() {
    	/* if(isset($_SERVER['HTTP_REFERER'])) {
			$referer_url_info = parse_url($_SERVER['HTTP_REFERER']);

			if(strpos($referer_url_info['host'], 'touch') !== false) {
				$this->_touch = true;	
				$referer_url_info['host'] = str_replace('touch', '', $referer_url_info['host']);
					
				if($referer_url_info['host'][0] == '.') {
					$referer_url_info['host'] = substr($referer_url_info['host'], 1);
				}
			}
				
        	if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
				$base_url_info = parse_url(my_base_url);
				
				if(strtolower($referer_url_info['host']) == strtolower($base_url_info['host'])) {
					$this->_ajax = true;
				}
        	} else if($this->_touch) {						
				$base_url_info = parse_url(my_base_url);

				if(strtolower($referer_url_info['host']) == strtolower($base_url_info['host'])) {
					$this->_ajax = true;
				}
			}
        } */
	 	if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
	 		$this->_ajax = true;
	 	}
        $this->_clean();
    }

    /**
     * Clean all input variables
     *
     */
    protected function _clean() {
        /*if ($_GET['alias']) {
            $aliasKey = $_GET['alias'];
            $aliasModel = OSC::model('core/alias', '')->loadByKey($aliasKey);

            if (!$aliasModel->getId()) {
                OSC::core('output')->notFound();
            }

            $this->_aliasKey = $_GET['alias'];

            $this->_aliasGetKeys = array_keys($aliasModel->getParams());

            $_GET = array_merge($_GET, $aliasModel->getParams());
            $_GET['controller'] = $aliasModel->getController();
        }

        if ($_GET['variables']) {
            if (!is_array($request)) {
                $request = array();
            }

            $request = array_merge($request, $this->parseGetRequest($_GET['variables']));
        }

        if (is_array($request)) {
            foreach ($request as $k => $v) {
                $_GET[$k] = $v;
            }
        }

        // Check if request backup exists, restore it

        if (isset($_GET['requestid']) && $_GET['requestid']) {
            $this->_restoreQueries($_GET['requestid']);
        }

        unset($_GET['alias']);
        unset($_GET['variables']);
        unset($_GET['requestid']);
*/
        $_GET = $this->_recursiveClean($_GET);
        $_POST = $this->_recursiveClean($_POST);

        $this->_getData = $_GET;
        $this->_postData = $_POST;

        $this->_origData = $this->_data = array_merge($this->_getData, $this->_postData);
    }

    /**
     * Recursive clean all input variables
     *
     * @param  array $data
     * @return array
     */
    protected function _recursiveClean($data) {
        //$format = OSC::core('format');

        foreach ($data as $k => $v) {
            if (is_array($v)) {
                $v = $this->_recursiveClean($v);
            } else {
                if (isset($_GET['_ajax_encode']) && $_GET['_ajax_encode']) {
                    $v = $this->_decodeAjax($v);
                }
				$v = htmlspecialchars($v);
                //$v = $format->clean($v);
            }

            $data[$k] = $v;
        }

        return $data;
    }
	
	public function decodeValue($value) {
		return htmlspecialchars_decode($value);
	}
	
	public function encodeValue($value) {
		return htmlspecialchars($value);
	}

    /**
     * Decode ajax variable string (UTF-8 encode)
     *
     * @param  string $txt
     * @return string
     */
    protected function _decodeAjax($txt) {
        if (!$txt) {
            return $txt;
        }

        return preg_replace('#%u([0-9A-F]{1,4})#ie', "\$this->_decodeUTF8(hexdec('\\1'))", utf8_encode($txt));
    }

    /**
     * Decode UTF-8
     *
     * @param  integer $int
     * @return string
     */
    protected function _decodeUTF8($int = 0) {
        $return = '';

        if ($int < 0) {
            return chr(0);
        } elseif ($int <= 0x007f) {
            $return .= chr($int);
        } elseif ($int <= 0x07ff) {
            $return .= chr(0xc0 | ( $int >> 6 ));
            $return .= chr(0x80 | ( $int & 0x003f ));
        } elseif ($int <= 0xffff) {
            $return .= chr(0xe0 | ( $int >> 12 ));
            $return .= chr(0x80 | ( ( $int >> 6 ) & 0x003f ));
            $return .= chr(0x80 | ( $int & 0x003f ));
        } elseif ($int <= 0x10ffff) {
            $return .= chr(0xf0 | ( $int >> 18 ));
            $return .= chr(0x80 | ( ( $int >> 12 ) & 0x3f ));
            $return .= chr(0x80 | ( ( $int >> 6 ) & 0x3f ));
            $return .= chr(0x80 | ( $int & 0x3f ));
        } else {
            return chr(0);
        }

        return $return;
    }

    public function isAjax() {
        return $this->_ajax;
    }

    /**
     * Get a input variable by key
     *
     * @param  string $key
     * @return string $return
     */
    public function get($key, $default = false) {
        return isset($this->_data[$key]) ? $this->_data[$key] : $default;
    }

    /**
     * Get more one input variables by key array
     *
     * @param  array $keys
     * @return array $return
     */
    public function gets($keys) {
        $vars = array();

        foreach ($keys as $key) {
            $vars[] = $this->get($key);
        }

        return $vars;
    }

    /**
     * Set a value to input variable by key
     *
     * @param  string $key
     * @param  mixed  $val
     * @return void
     */
    public function set($key, $val) {
        $this->_data[$key] = $val;
    }

    /**
     * Set value to more one input variables by key array
     *
     * @param  array $arr
     * @return void
     */
    public function sets($arr) {
        foreach ($arr as $key => $val) {
            $this->set($key, $val);
        }
    }

	/**
	 *
	 * @return OSCCore_Request
	 */

	public function reset() {
		$this->_data = $this->_getData = $this->_postData = array();
		return $this;
	}

    public function getGet($key = true, $default = false) {
        if ($key === true) {
            return $this->_getData;
        }
        return isset($this->_getData[$key]) ? $this->_getData[$key] : $default;
    }

    public function getPost($key = true, $default = false) {
        if ($key === true) {
            return $this->_postData;
        }
        return isset($this->_postData[$key]) ? $this->_postData[$key] : $default;
    }

    /**
     * Clean custom option form value
     *
     * @param array $form
     * @param array $rawVal
     * @return mixed
     */
    public function getCustomFormValues($form, $rawVal) {
        if ($rawVal === false) {
            return false;
        }

        if ($form['inputMethod'] < 3) {
            $value = $rawVal;

            if (!$value) {
                $value = false;
            }
        } elseif ($form['inputMethod'] == 4 || $form['inputMethod'] == 6) {
            $value = array();

            $buff = $rawVal;

            if (is_array($buff) && count($buff) > 0) {
                foreach ($buff as $val) {
                    if (array_key_exists($val, $form['optionContent']) && !in_array($val, $value)) {
                        $value[] = $val;
                    }
                }
            }

            if (count($value) < 1) {
                $value = false;
            }
        } elseif ($form['inputMethod'] == 3 || $form['inputMethod'] == 5) {
            $value = $rawVal;

            if (!array_key_exists($value, $form['optionContent'])) {
                $value = false;
            }
        } elseif ($form['inputMethod'] == 7) {
            $value = $rawVal == 1 ? 1 : 0;
        }

        if ($value !== false) {
            if ($form['saveCode'] != '') {
                $valToProcess = $value;

                eval($form['saveCode']);

                if ($valToProcess !== false) {
                    $value = $valToProcess;
                } else {
                    $value = false;
                }
            }
        }

        return $value;
    }

    /**
     * Save current queries and return a backup key
     *
     * @return String
     */
    public function backupQueries() {
        if (count($this->_origData) < 1) {
            return '';
        }

        $hash = md5(OSC::core('session')->sessionId);

        do {
            $bakID = OSC::core('function')->random(5);
            $tmpKey = 'request.' . $bakID . '.' . $hash . '.php';
        } while (OSC::core('filesystem_temporary')->exists($tmpKey));

        OSC::core('filesystem_temporary')->saveData(OSC::core('string')->convertDataToPHPContent(array('request' => $this->_origData, 'processor' => PROCESSOR), '__REQUEST'), $tmpKey, false);

        return $bakID;
    }

    /**
     * Restore a backup queries
     *
     * @param String $bakID
     * @return Boolean
     */
    protected function _restoreQueries($bakID) {
        $tmpKey = 'request.' . $bakID . '.' . md5(OSC::core('session')->sessionId) . '.php';

        if (!OSC::core('filesystem_temporary')->exists($tmpKey)) {
            return false;
        }

        include OSC::core('filesystem_temporary')->getPath($tmpKey);

        if ($__REQUEST['processor'] != PROCESSOR) {
            OSC::core('output')->redirect(OSCCONF::$baseUrl . '/' . ( $__REQUEST['processor'] == 'frontend' ? '' : ( $__REQUEST['processor'] == 'ucp' ? 'profile' : 'acp' ) . '.' ) . '?requestid=' . $bakID);
        }

        foreach($__REQUEST['request'] as $k => $v) {
            $_GET[$k] = $v;
        }

        OSC::core('filesystem_temporary')->delete($tmpKey);

        return true;
    }

    /**
     * get all of request variables
     *
     * @return array
     */
    public function getAll() {
        $data = $this->_data;

        unset($data['controller']);

        return $data;
    }

    /**
     * Remove a value by index
     *
     * @param String $key
     * @return void
     */
    public function remove($key) {
        unset($this->_data[$key]);
    }

    public function getCurrentUrl() {
        return $this->buildRequest($this->getAll());
    }

    public function getResourceUrl($file, $extension) {
        return OSCCONF::$baseUrl . '/' . ( OSCCONF::$usingRewrite ? '' : 'index.php/' ) . OSCCONF::$processors['resource'] . '/f/' . str_replace('/', '|', $file) . '.' . $extension;
    }

    public function rebuildUrl($params) {
        $params = array_merge($this->getGet(), $params);

        $keysToDestroy = $this->_aliasKey ? $this->_aliasGetKeys : array();

        $keysToDestroy[] = 'controller';

        foreach ($keysToDestroy as $keyToDestroy) {
            unset($params[$keyToDestroy]);
        }

        if ($this->_aliasKey) {
            return $this->getUrlByAlias($this->_aliasKey, $params);
        } else {
            return $this->getUrl(null, $params);
        }
    }

    public function getUrlByAlias($aliasKey, $params = array()) {
        if ($params === null) {
            $params = $this->getGet();
            unset($params['controller']);
        }

        return OSCCONF::$baseUrl . '/' . ( OSCCONF::$usingRewrite ? '' : 'index.php/' ) . $aliasKey . OSCCONF::$rewriteSuffix . '/' . $this->buildRequest($params);
    }

    public function getUrl($controller = null, $params = array(), $processor = null) {
        if (func_num_args() < 1) {
            $controller = null;
            $params = null;
            $getIn = null;
        }

        if (!array_key_exists($processor, OSCCONF::$processors)) {
            $processor = PROCESSOR;
        }

        if ($params === null) {
            $params = $this->getGet();
            unset($params['controller']);
        }

        if (is_array($controller)) {
            $controller = implode('_', $controller);

            if ($controller) {
                $controller = '_' . $controller;
            }

            $controller = substr(OSC::getCurrentController(), 0, strrpos(OSC::getCurrentController(), '_')) . $controller;
        } else if ($controller === null) {
            $controller = OSC::getCurrentController();
        } else if ($controller === false) {
            $controller = OSC::getDefaultController();
        }

        return OSCCONF::$baseUrl . '/' . ( OSCCONF::$usingRewrite ? '' : 'index.php/' ) . $processor . '/' . ( $controller ? $controller : OSC::getDefaultController() ) . '/' . $this->buildRequest($params);
    }

    public function buildRequest($request) {
		if(PROCESSOR == 'backend') {
			if(!is_array($request)) {
				$request = array();
			}

			$request['hash'] = OSC::processor()->getHash();
		}

        if (!is_array($request)) {
            return '';
        }

        $requestString = array();

        $openQuote = OSC::core('string')->cleanPattern(urlencode('{{'));
        $closeQuote = OSC::core('string')->cleanPattern(urlencode('}}'));

        foreach ($request as $k => $v) {
            $v = trim($v);

            if ($v === '') {
                continue;
            }

            $v = urlencode($v);

            if (strpos($v, urlencode('{{')) !== false) {
                $v = preg_replace('/' . $openQuote . '([a-z0-9_]+)' . $closeQuote . '/i', '{{\\1}}', $v);
            }

            if (strpos('/', $v) !== false) {
                $v = 'e.' . base64_encode($v);
            }

            $requestString[] = "{$k}/{$v}";
        }

        $requestString = implode('/', $requestString);

        return $requestString;
    }

    public function parseGetRequest($params) {
        $parsed = array();

        $params = trim($params);

        if ($params != '') {
            $params = preg_replace('/\/{2,}/', '/', $params);

            $segments = explode('/', $params);

            if (count($segments) > 1) {
                for ($key_idx = 0, $val_idx = 1; $val_idx < count($segments); $key_idx += 2, $val_idx += 2) {
                    $parsed[$segments[$key_idx]] = $segments[$val_idx];
                }
            }
        }

        return $parsed;
    }

    public function addParamsToUrl($url, $params) {
        if ($url === null) {
            $url = $this->rebuildUrl(array());
        }

        $url = preg_replace('//\/+$', '', $url);

        $params = $this->buildRequest($params);

        return $url . '/' . $path;
    }

}

?>